use ice::url::Url;
use webrtc_ice as ice;

use ice::agent::agent_config::AgentConfig;
use ice::agent::Agent;
use ice::candidate::candidate_base::*;
use ice::candidate::*;
use ice::network_type::*;
use ice::udp_network::UDPNetwork;
use ice::Error;
use std::io;
use std::sync::Arc;
use std::time::Duration;
use webrtc_ice::state::ConnectionState;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::DEBUG)
        .init();
    tracing::info!("RRAI 启动...");

    let ice_agent = Arc::new(
        Agent::new(AgentConfig {
            urls: vec![
                // Url::parse_url("stun:stun.l.google.com:19302")?,
                Url::parse_url("stun:39.106.1.82:3478")?,
            ],
            local_ufrag: String::from("RMZwDbbEWXXcUdKp"),
            local_pwd: String::from("DsyYKQPFTQGmIpqKsmYMJmZaiVWvUzqL"),
            network_types: vec![NetworkType::Udp4],
            ..Default::default()
        })
        .await?,
    );

    let (done_tx, mut done_rx) = tokio::sync::mpsc::channel::<()>(1);
    let done_tx = Arc::new(tokio::sync::Mutex::new(Some(done_tx)));

    ice_agent.on_candidate(Box::new(
        move |c: Option<Arc<dyn Candidate + Send + Sync>>| {
            let done_tx_clone = Arc::clone(&done_tx);
            Box::pin(async move {
                if c.is_none() {
                    let mut tx = done_tx_clone.lock().await;
                    tx.take();
                } else {
                    tracing::debug!("====:{}", c.unwrap().marshal());
                }
            })
        },
    ));

    ice_agent.on_connection_state_change(Box::new(move |c: ConnectionState| {
        tracing::debug!("ICE Connection State has changed: {c}");
        if c == ConnectionState::Failed {
            //
        }
        Box::pin(async move {})
    }));

    // ice_agent2.add_remote_candidate(&c);

    ice_agent.gather_candidates()?;

    let _ = done_rx.recv().await;
    tracing::debug!("gathering is done");

    tracing::debug!("Connecting...");

    let candidates = ice_agent.get_local_candidates().await?;

    // let (_cancel_tx, cancel_rx) = mpsc::channel(1);
    // // Start the ICE Agent. One side must be controlled, and the other must be controlling
    let remote_ufrag = String::from("");
    let remote_pwd = String::from("");

    // let conn = ice_agent.dial(done_rx, remote_ufrag, remote_pwd).await?;
    let conn = ice_agent.accept(done_rx, remote_ufrag, remote_pwd).await?;

    // let weak_conn = Arc::downgrade(&conn);
    // let conn_tx = Arc::clone(&conn);

    // let mut done_send = done_rx.clone();
    // tokio::spawn(async move {
    //     const RANDOM_STRING: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    //     loop {
    //         tokio::time::sleep(Duration::from_secs(3)).await;

    //         let val: String = (0..15)
    //             .map(|_| {
    //                 let idx = thread_rng().gen_range(0..RANDOM_STRING.len());
    //                 RANDOM_STRING[idx] as char
    //             })
    //             .collect();

    //         tokio::select! {
    //              _ = done_send.changed() => {
    //                 println!("receive cancel ice send!");
    //                 break;
    //             }
    //             result = conn_tx.send(val.as_bytes()) => {
    //                 if let Err(err) = result {
    //                     eprintln!("conn_tx send error: {err}");
    //                     break;
    //                 }else{
    //                     println!("Sent: '{val}'");
    //                 }
    //             }
    //         };
    //     }
    // });

    // let mut done_recv = done_rx.clone();
    // tokio::spawn(async move {
    //     // Receive messages in a loop from the remote peer
    //     let mut buf = vec![0u8; 1500];
    //     loop {
    //         tokio::select! {
    //             _ = done_recv.changed() => {
    //                 println!("receive cancel ice recv!");
    //                 break;
    //             }
    //             result = conn.recv(&mut buf) => {
    //                 match result {
    //                     Ok(n) => {
    //                         println!("Received: '{}'", std::str::from_utf8(&buf[..n]).unwrap());
    //                     }
    //                     Err(err) => {
    //                         eprintln!("conn_tx send error: {err}");
    //                         break;
    //                     }
    //                 };
    //             }
    //         };
    //     }
    // });

    println!("Press ctrl-c to stop");
    tokio::select! {
        _ = tokio::signal::ctrl_c() => {
            println!();
        }
    };
    Ok(())
}
